package com.cskaoyan.javase.object._6clone;

/**
 * 方法的声明
 * clone方法的方法声明为：
 * protected native Object clone() throws CloneNotSupportedException;
 * 这里需要注意的地方有：
 *      1.首先注意访问权限，它的访问权限是protected。
 *          这意味着：
 *          一般来说，只能在子类当中，创建子类自身对象才能够调用该方法（方法调用位置，肯定不是同包）。
 *      2.让一个类自身克隆自身，一般都没有多大意义，所以建议在子类中重写方法访问权限。
 *      3.它是一个本地native方法，没有方法体。（依赖本地方法实现创建对象，不同于new对象,和new创建对象是平行的关系,clone方法也不依赖于构造器）
 *      4.返回值类型是Object。
 *      5.throws CloneNotSupportedException是方法抛出异常的声明，这里我们先不管，后面异常的章节会讲解。
 *
 * 方法的作用:
 * Java当中的克隆方法clone()有类似的作用，当你在程序中有这种需求，即希望：
 *      1.得到一个和原先对象，完全独立的新对象。
 *      2.成员仍和原先对象一致。
 *
 * 有这种做法时，普通的做法就是再new一个一模一样的，但学习clone方法后，你就可以用该方法来做这个事情了。
 *
 * 所以Object类当中的clone方法默认实现
 *      就是得到一个独立的，和原先对象成员一致的新对象。
 *      一般来说,用默认实现就够了,一般不需要完全重写它的实现
 *
 *
 * clone方法怎么用?
 *      1.(必做)突破访问权限限制,在子类中重写访问权限
 *      2.(选做)Object类当中clone本地方法的默认实现,得到的对象一定
 *          和原先对象类型一致
 *          所以可以选择在子类重写返回值类型
 *      3.(必做)要想对某个类做克隆操作,那么该类必须实现接口
 *          java.lang.Cloneable
 *          否者,强行克隆,会导致程序抛出异常CloneNotSupportedException
 *
 *
 *  注意事项:
 *       1.Cloneable接口是一个什么接口?
 *          它是一个空接口
 *          在Java中,这种空接口,有一个特殊称呼"标记接口",被它标记(实现它)就允许做xx操作,否者就不允许
 *
 *      2.Object类当中的clone方法实现,是浅拷贝的:
 *          a.基本数据类型元素,直接单独复制一份
 *          b.引用数据类型元素,将引用复制一份,但原先对象和克隆对象中的引用,仍然指向同一个对象.
 *
 *          克隆方法目的是为了得到一个完全独立的新对象
 *          显然浅拷贝不符合这个特点
 *          所以引申出了深拷贝,深度克隆的概念
 *
 *          深拷贝,深度克隆指的是:
 *          得到一个完全和原先对象独立的新对象,不管类中成员变量是基本数据类型,还是引用数据类型
 *          具体步骤来说:
 *          1.深克隆是在浅克隆的基础上来完成.
 *          2.将对象中引用所指向的对象克隆一份
 *          3.将克隆对象中的克隆引用指向新的克隆对象
 *
 *
 *
 * @since 17:20
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) throws CloneNotSupportedException {
        /*Student s = new Student(18, 1000);
        Student cloneStu = s.clone();
        System.out.println(s == cloneStu);
        System.out.println(s.equals(cloneStu));*/

        Student s = new Student(18, 1000, new Star(208));
        Student cloneStu = s.clone();
        s.age = 28;
        System.out.println(cloneStu.age);

        s.star.salary = 1000;
        System.out.println(cloneStu.star.salary);
    }
}

// interface MyCloneable extends Cloneable {
// }

class Star implements Cloneable{
    double salary;

    public Star(double salary) {
        this.salary = salary;
    }

    @Override
    protected Star clone() throws CloneNotSupportedException {
        return (Star) super.clone();
    }
}

class Student implements Cloneable {
    int age;
    double score;
    Star star;

    public Student(int age, double score, Star star) {
        this.age = age;
        this.score = score;
        this.star = star;
    }

    public Student(int age, double score) {
        System.out.println("构造器执行了!!!");
        this.age = age;
        this.score = score;
    }

    @Override
    protected Student clone() throws CloneNotSupportedException {
        // 1.深克隆是在浅克隆的基础上来完成.
        Student cloneStu = (Student) super.clone();
        // 2.将对象中引用所指向的对象克隆一份
        Star cloneStar = star.clone();
        // 3.将克隆对象中的克隆引用指向新的克隆对象
        cloneStu.star = cloneStar;
        return cloneStu;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return Double.compare(student.score, score) == 0;
    }

    @Override
    public int hashCode() {
        int result;
        long temp;
        result = age;
        temp = Double.doubleToLongBits(score);
        result = 31 * result + (int) (temp ^ (temp >>> 32));
        return result;
    }
}